package com.zmn.oms.third.pinduoduo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.StatusConsts;
import com.zmn.oms.business.interfaces.third.PinDuoDuoSignShopService;
import com.zmn.oms.common.enums.ChannelFacade;
import com.zmn.oms.common.exception.chan.ChannelFacadeException;
import com.zmn.oms.common.exception.chan.DuplicateOrderClueException;
import com.zmn.oms.model.entity.chan.FacadeMessageEvent;
import com.zmn.oms.model.entity.chan.OrderClue;
import com.zmn.oms.model.entity.third.PinDuoDuoSignShop;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.third.core.interfaces.ChannelFacadeBService;
import com.zmn.oms.third.core.interfaces.FacadeMessageEventHandler;
import com.zmn.oms.third.pinduoduo.PinDuoDuoConsts;
import com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoCancelOrderParam;
import com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoCreateOrderParam;
import com.zmn.oms.third.pinduoduo.dto.api.PinDuoDuoResponse;
import com.zmn.oms.third.pinduoduo.service.PinDuoDuoBService;
import com.zmn.oms.third.pinduoduo.service.PinDuoDuoFacadeService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * 类描述：
 *
 * @author LiangHailong
 * @date 2021/01/01 23:46
 */
@Slf4j
@Service("pinDuoDuoFacadeService")
public class PinDuoDuoFacadeServiceImpl implements PinDuoDuoFacadeService, FacadeMessageEventHandler {

    @Autowired
    private PinDuoDuoSignShopService pinDuoDuoSignShopService;
    @Autowired
    private PinDuoDuoBService pinDuoDuoBService;
    @Autowired
    private ChannelFacadeBService channelFacadeBService;
    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;



    @Override
    public PinDuoDuoResponse handleSyncOrderMsg(Map<String, String> params) throws ChannelFacadeException {
        PinDuoDuoResponse pinDuoDuoResponse = new PinDuoDuoResponse();
        pinDuoDuoResponse.setSuccess(true);
        pinDuoDuoResponse.setErrorCode(PinDuoDuoConsts.ZMN_RETURN_CODE_SUCCESS);
        pinDuoDuoResponse.setErrorMsg("success");

        // 根据请求type不同进行处理
        String type = Optional.ofNullable(params)
                .map(map -> map.get("type"))
                .orElse("");
        switch (type){
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_ORDER_PUSH_FLAG:
                this.createOrder(params.get("request"));
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_APPOINT_NOTY_FLAG:
                this.appointOrder(params.get("request"));
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_ORDER_CACEL_FLAG:
                this.cancelOrder(params.get("request"));
                break;
            case PinDuoDuoConsts.PDD_SERVICE_AFTERSALES_SIGN_FLAG:
                this.signShop(params.get("request"));
                break;
            default:
                throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "参数错误");
        }
        return pinDuoDuoResponse;
    }

    @Override
    public boolean processEvent(FacadeMessageEvent event) {

        String evtTag = event.getTag();
        String fun = event.getFun();

        // 订单事件
        if (FacadeMessageEvent.EVENT_TAG_ORDER.equals(evtTag)) {
            switch (fun) {
                case PinDuoDuoConsts.FUN_NEW_ORDER: // 创建新单
                    return this.onCreateOrderEvent(event);
                case PinDuoDuoConsts.FUN_APPOINT_ORDER: // 预约通知
                    return this.onAppointOrderEvent(event);
                case PinDuoDuoConsts.FUN_CANCEL_ORDER:  // 取消订单
                    return this.onCancelOrderEvent(event);
            }
        }
        // 非订单事件
        else if (FacadeMessageEvent.EVENT_TAG_OTHER.equals(evtTag)) {
            if (PinDuoDuoConsts.FUN_SIGN_SHOP.equals(fun)) {
                // 店铺签约
                return this.onSignShopEvent(event);
            }
        }

        log.warn("【拼多多】未知的 FacadeMessageEvent: [{}]", JSON.toJSONString(event));

        return true;
    }

    @Override
    public String getTagFun(String eventTag, String eventFun, Integer channelId) {
        // 订单事件
        if (FacadeMessageEvent.EVENT_TAG_ORDER.equals(eventTag)) {
            switch (eventFun) {
                case PinDuoDuoConsts.FUN_NEW_ORDER: // 创建新单
                    return "创建新单";
                case PinDuoDuoConsts.FUN_APPOINT_ORDER: // 预约通知
                    return "预约通知";
                case PinDuoDuoConsts.FUN_CANCEL_ORDER:  // 取消订单
                    return "取消订单";
            }
        }
        // 非订单事件
        else if (FacadeMessageEvent.EVENT_TAG_OTHER.equals(eventTag)) {
            if (PinDuoDuoConsts.FUN_SIGN_SHOP.equals(eventFun)) {
                // 店铺签约
                return "店铺签约";
            }
        }

        return "未知";
    }

    /**
     * 根据线索创建订单
     * @param paramsStr
     * @return void
     * @author wangxiaokun
     */
    private void createOrder(String paramsStr) throws ChannelFacadeException {

        // 获取创建订单的具体内容
        PinDuoDuoCreateOrderParam createOrderParam = JSONObject.parseObject(paramsStr, PinDuoDuoCreateOrderParam.class);
        if (Objects.isNull(createOrderParam)){
            throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析创建订单参数失败");
        }

        // 查找店铺是否签约
        Long mallId = createOrderParam.getMallId();
        PinDuoDuoSignShop pinDuoDuoSignShop = pinDuoDuoSignShopService.findPinDuoDuoSignShopByMallId(mallId);
        if (Objects.isNull(pinDuoDuoSignShop) || pinDuoDuoSignShop.getSignStatus() != 1){
            throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "参数错误-店铺未申请签约");
        }

        String outerId = createOrderParam.getServOrderSn();

        // 创建新单Event
        FacadeMessageEvent event = new FacadeMessageEvent();
        event.setFacadeId(ChannelFacade.PINDUODUO.getId());
        event.setTag(FacadeMessageEvent.EVENT_TAG_ORDER);
        event.setFun(PinDuoDuoConsts.FUN_NEW_ORDER);
        event.setContent(paramsStr);
        event.setChannelId(pinDuoDuoSignShop.getChannelId());
        event.setOpTime(new Date());

        // 创建新单线索
        OrderClue orderClue = null;
        try {
            orderClue = channelFacadeBService.createOrderClue(event, outerId, false);
        } catch (DuplicateOrderClueException e) {
            log.info("【拼多多】重复的订单线索。 params=[{}]", paramsStr);
            return;
        } catch (ChannelFacadeException e) {
            log.error(String.format("【拼多多】保存订单线索失败: %s。 params=[%s]", e.getMessage(), paramsStr));
            throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "保存订单线索失败");
        }

        // 通知系统创建新单
        event.setClueId(orderClue.getId());
        event.setMessageNo(orderClue.getMessageNo());
        channelFacadeBService.sendFacadeMessageEvent(event);
    }

    /**
     * 根据线索创建订单
     * @param event
     * @return 是否处理完成，如果返回false，会触发重试
     */
    private boolean onCreateOrderEvent(FacadeMessageEvent event) {

        OrderClue dbOrderClue = channelFacadeBService.findOrderClueByOrderClueId(event.getClueId());
        if (dbOrderClue == null) {
            channelFacadeBService.saveFacadeMessageEventError(event, "录单失败：未找到对应的订单线索");
            return false;   // 稍后重试
        }
        if (!Objects.equals(0L, dbOrderClue.getZmnOrderId())) {
            return true;    // 已录入成功，不再重复录单
        }

        try {
            pinDuoDuoBService.createOrder(dbOrderClue, event.getContent());
        } catch (ChannelFacadeException e) {
            log.error(e.getMessage(), e);
            channelFacadeBService.saveFacadeMessageEventError(event, String.format("录单失败：%s", e.getMessage()));

            int errorCode = Optional.ofNullable(e.getCode()).orElse(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN);
            return errorCode > 200; // 错误码超过200，不再重试
        }

        return true;
    }

    /**
     * 预约通知处理
     * @param paramsStr
     * @return void
     * @author wangxiaokun
     */
    private void appointOrder(String paramsStr) throws ChannelFacadeException {
        // 获取预约通知的具体内容
        PinDuoDuoCreateOrderParam createOrderParam = JSONObject.parseObject(paramsStr, PinDuoDuoCreateOrderParam.class);
        if (Objects.isNull(createOrderParam)){
            throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析预约通知参数失败");
        }

        String outerId = createOrderParam.getServOrderSn();

        // 通知系统处理预约通知
        FacadeMessageEvent event = new FacadeMessageEvent();
        event.setFacadeId(ChannelFacade.PINDUODUO.getId());
        event.setTag(FacadeMessageEvent.EVENT_TAG_ORDER);
        event.setFun(PinDuoDuoConsts.FUN_APPOINT_ORDER);
        event.setContent(paramsStr);
        event.setOpTime(new Date());

        OrderClue orderClue = null;
        try {
            orderClue = channelFacadeBService.receiveOrderBizMessage(event, outerId, null);
        } catch (ChannelFacadeException e) {
            log.error(String.format("【拼多多】保存订单预约通知消息失败: %s。 params=[%s]", e.getMessage(), paramsStr));
            throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "保存订单预约通知消息失败");
        }

        if (orderClue != null) {
            event.setClueId(orderClue.getId());
            event.setMessageNo(orderClue.getMessageNo());
        }
        // 兼容未通过渠道门户API接入的订单
        else {
            ZsOrderWorkVO dbOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(outerId, null);
            if (dbOrderWorkVO == null) {
                throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "未找到对应订单");
            }
            event.setZmnOrderId(dbOrderWorkVO.getOrderId());
            event.setChannelId(dbOrderWorkVO.getChannelId());
        }

        channelFacadeBService.sendFacadeMessageEvent(event);
    }

    /**
     * 预约通知处理
     * @param event
     * @return 是否处理完成，如果返回false，会触发重试
     */
    protected boolean onAppointOrderEvent(FacadeMessageEvent event) {

        OrderClue dbOrderClue = null;
        if (event.getClueId() != null) {
            dbOrderClue = channelFacadeBService.findOrderClueByOrderClueId(event.getClueId());
            if (dbOrderClue == null || dbOrderClue.getZmnOrderId() == null) {
                channelFacadeBService.saveFacadeMessageEventError(event, "预约失败：未找到对应的订单线索");
                return false;   // 稍后重试
            }
        }

        // 兼容未通过渠道门户API接入的订单
        if (dbOrderClue == null && event.getZmnOrderId() != null) {
            dbOrderClue = new OrderClue();
            dbOrderClue.setZmnOrderId(event.getZmnOrderId());
        }

        try {
            pinDuoDuoBService.appointOrder(dbOrderClue, event.getContent());
        } catch (ChannelFacadeException e) {
            log.error(e.getMessage(), e);
            channelFacadeBService.saveFacadeMessageEventError(event, String.format("预约失败：%s", e.getMessage()));

            int errorCode = Optional.ofNullable(e.getCode()).orElse(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN);
            return errorCode > 200; // 错误码超过200，不再重试
        }

        return true;
    }

    /**
     * 处理拼多多取消订单的请求
     * @param paramsStr
     * @return void
     * @author wangxiaokun
     */
    private void cancelOrder(String paramsStr) throws ChannelFacadeException {

        // 获取取消订单的具体内容
        PinDuoDuoCancelOrderParam paramCancelOrder = JSONObject.parseObject(paramsStr, PinDuoDuoCancelOrderParam.class);
        if (Objects.isNull(paramCancelOrder)) {
            throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析取消订单参数失败");
        }

        String outerId = paramCancelOrder.getServOrderSn();

        // 通知系统处理预约通知
        FacadeMessageEvent event = new FacadeMessageEvent();
        event.setFacadeId(ChannelFacade.PINDUODUO.getId());
        event.setTag(FacadeMessageEvent.EVENT_TAG_ORDER);
        event.setFun(PinDuoDuoConsts.FUN_CANCEL_ORDER);
        event.setContent(paramsStr);
        event.setOpTime(new Date());

        OrderClue orderClue = null;
        try {
            orderClue = channelFacadeBService.receiveOrderBizMessage(event, outerId, null);
        } catch (ChannelFacadeException e) {
            log.error(String.format("【拼多多】保存取消订单消息失败: %s。 params=[%s]", e.getMessage(), paramsStr));
            throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "保存取消订单消息失败");
        }

        if (orderClue != null) {
            event.setClueId(orderClue.getId());
            event.setMessageNo(orderClue.getMessageNo());
        }
        // 兼容未通过渠道门户API接入的订单
        else {
            ZsOrderWorkVO dbOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(outerId, null);
            if (dbOrderWorkVO == null) {
                throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "未找到对应订单");
            }
            event.setZmnOrderId(dbOrderWorkVO.getOrderId());
            event.setChannelId(dbOrderWorkVO.getChannelId());
        }

        channelFacadeBService.sendFacadeMessageEvent(event);
    }

    /**
     * 取消订单
     * @param event
     * @return 是否处理完成，如果返回false，会触发重试
     */
    private boolean onCancelOrderEvent(FacadeMessageEvent event) {
        OrderClue dbOrderClue = null;
        if (event.getClueId() != null) {
            dbOrderClue = channelFacadeBService.findOrderClueByOrderClueId(event.getClueId());
            if (dbOrderClue == null || dbOrderClue.getZmnOrderId() == null) {
                channelFacadeBService.saveFacadeMessageEventError(event, "取消订单失败：未找到对应的订单线索");
                return false;   // 稍后重试
            }
        }
        // 兼容未通过渠道门户API接入的订单
        if (dbOrderClue == null && event.getZmnOrderId() != null) {
            dbOrderClue = new OrderClue();
            dbOrderClue.setZmnOrderId(event.getZmnOrderId());
        }

        try {
            pinDuoDuoBService.cancelOrder(dbOrderClue, event.getContent());
        } catch (ChannelFacadeException e) {
            log.error(e.getMessage(), e);
            channelFacadeBService.saveFacadeMessageEventError(event, String.format("取消订单失败：%s", e.getMessage()));

            int errorCode = Optional.ofNullable(e.getCode()).orElse(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN);
            return errorCode > 200; // 错误码超过200，不再重试
        }

        return true;
    }

    /**
     * 处理店铺签约请求
     * @param paramsStr
     * @return void
     * @author wangxiaokun
     */
    private void signShop(String paramsStr) throws ChannelFacadeException {
        if (StringUtils.isBlank(paramsStr)){
            throw new ChannelFacadeException(PinDuoDuoConsts.ZMN_RETURN_CODE_PARAM_ERROR, "解析店铺签约参数失败");
        }

        // 通知系统处理店铺签约
        FacadeMessageEvent event = new FacadeMessageEvent();
        event.setFacadeId(ChannelFacade.PINDUODUO.getId());
        event.setTag(FacadeMessageEvent.EVENT_TAG_OTHER);
        event.setFun(PinDuoDuoConsts.FUN_SIGN_SHOP);
        event.setContent(paramsStr);
        event.setOpTime(new Date());

        try {
            channelFacadeBService.receiveNonOrderMessage(event);
        } catch (ChannelFacadeException e) {
            log.error(String.format("【拼多多】保存店铺签约消息失败: %s。 params=[%s]", e.getMessage(), paramsStr));
            throw new ChannelFacadeException(StatusConsts.STATUS_ERROR, "保存店铺签约消息失败");
        }


        channelFacadeBService.sendFacadeMessageEvent(event);
    }

    /**
     * 处理服务签约请求
     * @param event
     * @return 是否处理完成，如果返回false，会触发重试
     */
    private boolean onSignShopEvent(FacadeMessageEvent event) {
        try {
            pinDuoDuoBService.signShop(event.getContent());
        } catch (ChannelFacadeException e) {
            log.error(e.getMessage(), e);
            channelFacadeBService.saveFacadeMessageEventError(event, String.format("服务签约失败：%s", e.getMessage()));

            int errorCode = Optional.ofNullable(e.getCode()).orElse(PinDuoDuoConsts.ERROR_CODE_SERVER_UNKNOWN);
            return errorCode > 200; // 错误码超过200，不再重试
        }

        return true;
    }
}
